package com.vteba.security.manager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;

import com.vteba.security.user.Authority;
import com.vteba.security.user.IUserDetails;
import com.vteba.security.user.Resource;

public class DefaultWebSecurityPrivilegeManager {
	private boolean authPriority;
	
	private AbstractSecurityInterceptor filterSecurityInterceptorImpl;
	private AccessDecisionManager accessDecisionManagerImpl;
	@SuppressWarnings("unused")
	private AbstractSecurityInterceptor methodSecurityInterceptorImpl;

	/**
	 * 验证权限
	 * @param auth 权限名，多个以逗号分隔
	 * @param contextPath 上下文路径
	 * @return true有权限，false没有
	 */
	public boolean authorizeAuth(String auth, String contextPath) {
		// 获取标签配置的权限
		Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
		String[] authArray = StringUtils.split(auth, ",");
		for (String auths : authArray) {
			SecurityConfig config = new SecurityConfig(auths);
			configAttributes.add(config);
		}
		boolean result = false;
		try {
			// 调用访问决策管理器验证
			accessDecisionManagerImpl.decide(getUserToken(), contextPath, configAttributes);
			result = true;
		} catch (Exception e) {
			result = false;
		}
		return result;
	}
	
	/**
	 * 验证方法
	 * @param method 待验证方法，包含包名
	 * @param contextPath 上下文路径
	 * @return 可以访问true，false不可访问
	 */
	// 应该使用aop，这种方式也是可以的
	public boolean authorizeMethod(String method, String contextPath) {
		if (getUserToken() == null) {
			return false;
		}

		// 这里进行权限判断，防止没有权限，但是有资源权限
//		if (authPriority) {
//			try {
//				accessDecisionManagerImpl.decide(getUserToken(), fi, attrs);
//			} catch (AccessDeniedException unauthorized) {
//				return false;
//			}
//		}
		
		IUserDetails user = getUser();
		List<? extends Authority> authorityList = user.getAuthorityList();
		for (Authority auth : authorityList) {
			// 如果当前用户拥有这个url的权限
			if (auth.getMethodResource().contains(method)) {
				return true;
				// break;//效果一样
			} else {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * 验证url
	 * @param url url
	 * @param contextPath 上下文路径
	 * @return 可以访问true，false不可访问
	 */
	public boolean authorizeUrl(String url, String contextPath) {
		if (getUserToken() == null) {
			return false;
		}
		
		// 这里进行权限判断，防止没有权限，但是有资源权限
		if (authPriority) {
			FilterInvocation fi = new FilterInvocation(contextPath, url, null);
			// 获取该url对应的权限
			Collection<ConfigAttribute> attrs = filterSecurityInterceptorImpl
					.obtainSecurityMetadataSource().getAttributes(fi);

			// 是否对公共资源放开，这里是放开
			if (attrs == null) {
				if (filterSecurityInterceptorImpl.isRejectPublicInvocations()) {
					return false;
				}
				return true;
			}
			try {
				accessDecisionManagerImpl.decide(getUserToken(), fi, attrs);
			} catch (AccessDeniedException unauthorized) {
				return false;
			}
		}
		
		IUserDetails user = getUser();
		List<? extends Authority> authorityList = user.getAuthorityList();
		for (Authority auth : authorityList) {
			// 如果当前用户拥有这个url的权限
			Set<String> resouceSet = auth.getUrlResource();
			if (resouceSet != null && resouceSet.contains(url)) {
				return true;
			}
		}
		return false;
	}
	
	public boolean authorizeResource(String type, String resource, String contextPath) {
		if (Resource.METHOD.equals(type)) {
			return authorizeMethod(resource, contextPath);
		} else if (Resource.URL.equals(type)) {
			return authorizeUrl(resource, contextPath);
		}
		return false;
	}
	
	public Authentication getUserToken() {
		return SecurityContextHolder.getContext().getAuthentication();
	}
	
	public IUserDetails getUser() {
		return (IUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
	}
	
	public void setFilterSecurityInterceptorImpl(
			AbstractSecurityInterceptor filterSecurityInterceptorImpl) {
		this.filterSecurityInterceptorImpl = filterSecurityInterceptorImpl;
	}

	public void setAccessDecisionManagerImpl(AccessDecisionManager accessDecisionManagerImpl) {
		this.accessDecisionManagerImpl = accessDecisionManagerImpl;
	}

	public void setMethodSecurityInterceptorImpl(AbstractSecurityInterceptor methodSecurityInterceptorImpl) {
		this.methodSecurityInterceptorImpl = methodSecurityInterceptorImpl;
	}

	public boolean isAuthPriority() {
		return authPriority;
	}

	public void setAuthPriority(boolean authPriority) {
		this.authPriority = authPriority;
	}

}
